!! Copyright (C) 2009,2010,2011,2012  Marco Restelli
!!
!! This file is part of:
!!   FEMilaro -- Finite Element Method toolkit
!!
!! FEMilaro is free software; you can redistribute it and/or modify it
!! under the terms of the GNU General Public License as published by
!! the Free Software Foundation; either version 3 of the License, or
!! (at your option) any later version.
!!
!! FEMilaro is distributed in the hope that it will be useful, but
!! WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
!! General Public License for more details.
!!
!! You should have received a copy of the GNU General Public License
!! along with FEMilaro; If not, see <http://www.gnu.org/licenses/>.
!!
!! author: Marco Restelli                   <marco.restelli@gmail.com>

!> Interface to the SeLaLib working precision module
!!
!! Here we define the working precision \c wp as the precision of \c
!! sll_real, since this is the SeLaLib kind which allows changing the
!! working precision of the whole library. Notice that when using
!! SeLaLib procedures one might include a conversion to \c sll_real32
!! and \c sll_real64 if these do not coincide with \c sll_real.
!!
!! Concerning the integer kinds, we don't define anything since the
!! idea in FEMilaro is using the default integer unless there is a
!! specific reason for a different choice, in which case the
!! corresponding definitions should be placed directly in the relevant
!! modules. This happens, for instance, for modules interfacing to
!! external libraries, such as the linear solvers. Then, the best
!! solution is that each module defines a specific kind, and
!! conversions are always performed, even if they are trivial.
module mod_kinds
!-----------------------------------------------------------------------

#include "sll_working_precision.h"

!-----------------------------------------------------------------------

 use mod_messages, only: &
   mod_messages_initialized, &
   error,   &
   warning, &
   info

!-----------------------------------------------------------------------
 
 implicit none

!-----------------------------------------------------------------------

! Module interface

 public :: &
   mod_kinds_constructor, &
   mod_kinds_destructor,  &
   mod_kinds_initialized, &
   wp, wp_p, wp_r

 private

!-----------------------------------------------------------------------

! Module types and parameters

 ! public members

 !----------------------------------------------------------------------
 ! Select here the working precision wp

 sll_real :: sll_real_example ! no need to assign any value
 integer, parameter :: wp = kind(sll_real_example)

 !----------------------------------------------------------------------

! Module variables

 ! public members
 integer, parameter :: &
   wp_p = precision(1.0_wp), &
   wp_r = range(1.0_wp)
 logical, protected ::               &
   mod_kinds_initialized = .false.
 ! private members
 character(len=*), parameter :: &
   this_mod_name = 'mod_kinds'

!-----------------------------------------------------------------------

contains

!-----------------------------------------------------------------------

 subroutine mod_kinds_constructor()

  character(len=100) message(3)
  character(len=*), parameter :: &
    this_sub_name = 'constructor'

   !Consistency checks ---------------------------
   if( (mod_messages_initialized.eqv..false.) ) then
     call error(this_sub_name,this_mod_name, &
                'Not all the required modules are initialized.')
   endif
   if(mod_kinds_initialized.eqv..true.) then
     call warning(this_sub_name,this_mod_name, &
                  'Module is already initialized.')
   endif
   !----------------------------------------------

   write(message(1),'(A,I3)') 'working precision wp = ', wp
   write(message(2),'(A,I5)') 'precision = ', wp_p
   write(message(3),'(A,I5)') 'range = ', wp_r
   call info(this_sub_name,this_mod_name,message)

   mod_kinds_initialized = .true.
 end subroutine mod_kinds_constructor

!-----------------------------------------------------------------------
 
 subroutine mod_kinds_destructor()
  character(len=*), parameter :: &
    this_sub_name = 'destructor'
   
   !Consistency checks ---------------------------
   if(mod_kinds_initialized.eqv..false.) then
     call error(this_sub_name,this_mod_name, &
                'This module is not initialized.')
   endif
   !----------------------------------------------

   mod_kinds_initialized = .false.
 end subroutine mod_kinds_destructor

!-----------------------------------------------------------------------

end module mod_kinds

